#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Licensed Materials - Property of tenxcloud.com
# (C) Copyright 2020 TenxCloud. All Rights Reserved.
# 2020-05-31 @author lizhen

from flask import Blueprint, jsonify, request, current_app, abort

from data_set_api.model import db, DataSet, File, DataSetPhase
from data_set_api.utils import short_uuid, save_file
from data_set_api.root import john_doe

from datetime import datetime
from pathlib import Path
from functools import wraps

import os
import shutil

blueprint = Blueprint('data_set', __name__, url_prefix="/datasets")


def ensure_data_set(api):
    @wraps(api)
    def find_data_set(data_set_id):
        data_set = DataSet.query.get(data_set_id)
        if data_set is None:
            abort(404, "data set not found")
        return api(data_set_id, data_set)

    return find_data_set


@blueprint.route('/<string:data_set_id>', methods=['GET'], strict_slashes=False)
@ensure_data_set
def get(data_set_id, data_set):
    return jsonify(data_set)


@blueprint.route('', methods=['GET'], strict_slashes=False)
def list_all():
    raw_public = request.args.get('public')
    query = {}
    if raw_public is not None:
        query['public'] = raw_public.lower() in ['true', '1', 't', 'y', 'yes']

    attribute = request.args.get('attribute', default=-1, type=int)
    if attribute != -1:
        query['attribute'] = attribute

    raw_phase = request.args.get('phase')
    if raw_phase is not None:
        try:
            phase = DataSetPhase[raw_phase]
        except KeyError:
            abort(400, "phase: only raw, processed, processing supported")
        else:
            query['phase'] = phase

    data_sets = DataSet.query.filter_by(**query).all()

    return jsonify(data_sets)


@blueprint.route('', methods=['POST'], strict_slashes=False)
def create():
    data_set_id = short_uuid()
    data_set_folder = os.path.join(
        current_app.config['FILE_FOLDER_ROOT'], data_set_id)

    Path(data_set_folder).mkdir(parents=True, exist_ok=True)

    data_set = DataSet(
        id=data_set_id,
        create_at=datetime.now(),
        create_by=john_doe,
        public=True,
        name=request.form.get('name'),
        description=request.form.get('detail'),
        attribute=request.form.get('attribute', default=0, type=int),
        files=[File(**save_file(file, data_set_id, data_set_folder))
               for file in request.files.getlist("files")]
    )

    db.session.add(data_set)
    db.session.commit()

    return jsonify(data_set), 201


@blueprint.route('/<string:data_set_id>', methods=['DELETE'], strict_slashes=False)
@ensure_data_set
def delete(data_set_id, data_set):
    db.session.query(File).filter(
        File.data_set_id == data_set_id).delete(synchronize_session=False)
    db.session.delete(data_set)

    shutil.rmtree(
        os.path.join(current_app.config['FILE_FOLDER_ROOT'], data_set.id),
        ignore_errors=True)

    db.session.commit()

    return "", 204


@blueprint.route('/<string:data_set_id>', methods=['PATCH'], strict_slashes=False)
@ensure_data_set
def update(data_set_id, data_set):
    if not request.content_type.startswith('application/json'):
        abort(400, "bad request body, only json supported")

    name = request.json.get('name')
    if name is not None:
        data_set.name = name
    description = request.json.get('detail')
    if description is not None:
        data_set.description = description
    public = request.json.get('public')
    if public is not None:
        data_set.public = public
    attribute = request.json.get('attribute')
    if attribute is not None:
        data_set.attribute = attribute

    db.session.commit()

    return "", 204
